package com.myex.demo.controller;


import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.myex.demo.common.mq.MQSender;
import com.myex.demo.common.result.CommonResult;
import com.myex.demo.common.util.RedisUtil;
import com.myex.demo.model.Goods;
import com.myex.demo.model.OrderMsg;
import com.myex.demo.model.OrderRecord;
import com.myex.demo.service.MiaoShaService;
import com.myex.demo.service.TestPageService;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/miaosha")
public class MiaoShaController implements InitializingBean {

    @Autowired
    MiaoShaService miaoShaService;
    @Autowired
    TestPageService testPageService;
    @Autowired
    RedissonClient redissonClient;

    @Autowired
    MQSender mqSender;


    //内存标记，库存时候为0 ，是否秒杀结束，减少redis访问
    private HashMap<String, Boolean> localOverMap =  new HashMap<String, Boolean>();


    /**
     *  step 1,系统初始化时把商品加入到缓存中
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<Goods> stockList = miaoShaService.selectAllGoods();
        System.out.println("系统初始化："+stockList);
        if (stockList.size() <= 0){
            return;
        }
        for (Goods goods: stockList) {
            //将库存加载到redis中
            RedisUtil.set(goods.getId()+"",goods.getGoodsStock()+"");
            //添加内存标记
            localOverMap.put(goods.getId()+"", false);
        }

    }


    /**
     * step 2  请求秒杀,redis+rabbitmq方式
     *
     * 利用redis的单线程预减库存。比如商品有100件。那么我在redis存储一个k,v。例如 <gs1001, 100>
     * 每一个用户线程进来，key值就减1，等减到0的时候，全部拒绝剩下的请求。
     * 那么也就是只有100个线程会进入到后续操作。所以一定不会出现超卖的现象
     *
     * (也可以用乐观锁解决超卖问题，即采用了版本号的方式，其实也就是CAS的原理)
     * update goods set num = num - 1, version = version + 1 WHERE id= #{id} AND num > 0 AND version = #{version}(上面查到的version);
     *
     */
    @RequestMapping(value="/go",method = RequestMethod.GET)
    @ResponseBody
    public Object miaoshaGo(@RequestParam("userId") String userId,
                            @RequestParam("goodsId") String goodsId,
                            @RequestParam("num") String num){
        if(StrUtil.isEmpty(userId) || StrUtil.isEmpty(goodsId) || StrUtil.isEmpty(num)){
            return CommonResult.failed("参数不全");
        }
        //根据需求校验是否频繁请求
        if(localOverMap.get(goodsId)) {
            return CommonResult.success("商品"+goodsId+"已售空");
        }
        //调用redis给相应商品库存量减去
        long stock = RedisUtil.decr(goodsId,Long.parseLong(num));
        if (stock<=0){
            localOverMap.put(goodsId,true);
        }
        System.out.println("Redis剩余库存：" + stock);
        //加入到队列中，客户端轮询或延迟几秒后查看结果
        mqSender.send(new OrderMsg(userId,goodsId,num));
        return CommonResult.success("排队中!");
    }


    //查询秒杀结果(orderId：成功,-1：秒杀失败,0： 排队中)
    @RequestMapping(value="/result", method= RequestMethod.GET)
    public Object miaoshaResult(@RequestParam("userId") String userId,
                                          @RequestParam("goodsId") String goodsId) {
        OrderMsg result = miaoShaService.getMiaoShaResult(userId, goodsId);
        if (result != null){
            return CommonResult.success(result,"秒杀成功");
        }else {
            boolean isOver = miaoShaService.getGoodsOver(goodsId);
            if (isOver){
                return CommonResult.failed("售完，秒杀失败!");
            }else {
                return CommonResult.failed("未售完，秒杀失败!");
            }
        }

    }


    /**
     * 测试mybatis-plus分页插件
     */
    @RequestMapping("/testPage")
    public CommonResult<IPage<OrderRecord>> testPage(
                                                    @RequestParam("currentPage") int page,
                                                    @RequestParam("size") int size){
        return CommonResult.success(testPageService.listOrder(page,size));
    }


    @RequestMapping("/selectAllGoods")
    public List<Goods> selectAllGoods(){
       return miaoShaService.selectAllGoods();
    }


    @RequestMapping("/selectGoods")
    public Goods selectGoods(@RequestParam("goodsId") String goodsId){
        return miaoShaService.findGoods(goodsId);
    }


    /**
     * 测试使用redisson
     */
    @RequestMapping(value = "/testRedison",method = RequestMethod.GET)
    public void testRedison(@RequestParam("userId") String userId,
                            @RequestParam("goodsId") String goodsId,
                            @RequestParam("num") String num){
        String lockKey = "lockKey";
        RLock redissonLock = redissonClient.getLock(lockKey);//（1）拿一个Redisson的锁对象
        try{
            redissonLock.lock();//（2）加锁，底层默认设置超时时间为30s
            //（3）减库存操作
            int stock = Integer.parseInt((String) RedisUtil.get("stock"));
            if(stock > 0){
                int realStock = stock - Integer.parseInt(num);
                RedisUtil.set("stock",realStock + "");
                System.out.println("扣减成功，剩余库存" + realStock);
            } else {
                System.out.println("扣减失败，库存不足");
            }
        }finally{
            redissonLock.unlock();//（4）释放锁
        }
    }

}
